package com.xz.knowledgeDuplication.pattern.framework.beans.context.support;

import com.xz.knowledgeDuplication.pattern.framework.beans.BeanDefinition;
import com.xz.knowledgeDuplication.pattern.framework.beans.MutablePropertyValues;
import com.xz.knowledgeDuplication.pattern.framework.beans.PropertyValue;
import com.xz.knowledgeDuplication.pattern.framework.beans.factory.support.BeanDefinitionRegistry;
import com.xz.knowledgeDuplication.pattern.framework.beans.factory.xml.XmlBeanDefinitionReader;

import java.lang.reflect.Method;

/**
 * 用于加载xml格式配置文件
 *
 * @author 召
 * @date 2022-04-11 21:59:38
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        // 构建解析器对象
        this.beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String name) throws Exception {
        // 根据名称获取对应bean对象
        Object obj = this.singletonObjects.get(name);
        if (obj != null) {
            return obj;
        }
        // 获取注册表对象 由于执行refresh方法,所以的beanDefinition对象已经被添加到注册表中
        BeanDefinitionRegistry registry = this.beanDefinitionReader.getRegistry();
        // 获取对应的beanDefinition对象
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        if (beanDefinition == null) {
            return null;
        }
        // 获取className属性
        String className = beanDefinition.getClassName();
        // 获取class属性,并创建对象
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();
        // 获取property标签中的内容并注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            // 获取name属性
            String propertyValueName = propertyValue.getName();
            // 获取ref属性
            String ref = propertyValue.getRef();
            // 获取value属性
            String value = propertyValue.getValue();
            // eg: setXyz
            String methodName = "set" + propertyValueName.substring(0, 1).toUpperCase() + propertyValueName.substring(1);
            // 非String和基本数据类型
            if (ref != null && !"".equals(ref)) {
                // 递归获取对应bean
                Object bean = getBean(ref);
                // 获取对应的set方法
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (method.getName().equals(methodName)) {
                        method.invoke(beanObj, bean);
                    }
                }
            }
            // String和基本数据类型
            if(value != null && !"".equals(value)) {
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (method.getName().equals(methodName)) {
                        method.invoke(beanObj, value);
                    }
                }
            }

        }
        // 将bean存入容器中
        this.singletonObjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if(bean != null) {
            return clazz.cast(bean);
        }
        return null;
    }
}
